Skip to content

feat(scanner): add inline suppression annotations (# ai-bom: ignore)#79

Open
Automation-Dude wants to merge 1 commit intoTrusera:mainfrom
Automation-Dude:feat/inline-suppression-annotations
Open

feat(scanner): add inline suppression annotations (# ai-bom: ignore)#79
Automation-Dude wants to merge 1 commit intoTrusera:mainfrom
Automation-Dude:feat/inline-suppression-annotations

Conversation

@Automation-Dude
Copy link
Copy Markdown

Summary

Add two comment-based suppression directives to \CodeScanner\ that let
developers mark intentional AI SDK usage, preventing false positives without
having to exclude entire directories via .ai-bomignore.

\\python
import openai # ai-bom: ignore <- suppresses SDK detection on this line

ai-bom: ignore-file <- place in first 5 lines; suppresses

import openai # SDK detection for the entire file
\\

The problem this solves

.ai-bomignore\ handles path-level suppression well, but it is too coarse when
only a handful of lines in a file are the source of false positives. The most
common case: a project's own detection engine contains AI SDK names as string
literals (regex patterns, config data) -- not as live runtime dependencies.
Scanning ai-bom itself with ai-bom demonstrates this: 162 components are
reported, all false positives from the pattern definition files.

Design decision: API key detection is unconditional

Our initial implementation suppressed all detection on an annotated line,
including hardcoded API key findings. We reconsidered this.

The two detection types are categorically different:

Detection Nature Can be intentional?
SDK component (import/usage) Inventory finding Yes -- reviewed, declared
Hardcoded API key Security finding No -- never safe in source

Suppressing shadow AI detection does not break the security intent of the tool.
Suppressing credential detection would. A developer tagging an import as
intentional should not inadvertently silence a leaked key on the same line.

This is consistent with how comparable tools handle the same tension:

  • \�andit's # nosec\ README explicitly warns against suppressing credential rules
  • \detect-secrets\ uses a separate allow-list rather than inline suppression for secrets
  • \semgrep's # nosemgrep\ follows the same scope-limited pattern

Result: # ai-bom: ignore\ and # ai-bom: ignore-file\ suppress SDK/component
detection only. \hardcoded_api_key\ findings always fire.

Idiomatic precedent

Tool Annotation
flake8 / ruff # noqa\
mypy # type: ignore\
bandit # nosec\
ai-bom # ai-bom: ignore\

Annotations

Annotation Scope Suppresses
# ai-bom: ignore\ Single line SDK/component detection on that line
# ai-bom: ignore-file\ Entire file SDK/component detection in the file (must appear in first 5 lines)

Use cases

  • Tool self-scans where pattern definition files contain SDK names as string literals
  • Test harnesses that reference SDK names to test detection behavior
  • Compatibility shim code that checks for SDK presence without loading it
  • Documentation generators that embed SDK names as examples

Quality gates

All three gates pass on Python 3.10-3.13:

\
ruff check src/ tests/ -- 0 errors
mypy src/ai_bom/ -- 0 errors
pytest -v -- 806 passed, 21 skipped
\\

Tests added (8 new cases in \TestInlineSuppression)

  • Line-level # ai-bom: ignore\ suppresses SDK detection
  • Line-level annotation does not suppress hardcoded API key detection
  • File-level annotation does not suppress hardcoded API key detection
  • Suppressed lines do not affect other lines in the same file
  • # ai-bom: ignore-file\ skips all SDK detection in the file
  • File-level annotation is honoured on lines 2-5, not only line 1
  • File-level annotation after line 5 has no effect
  • Files without any annotation are unaffected

Add two comment-based suppression directives to CodeScanner that let
developers mark intentional AI SDK usage, preventing false positives
without having to exclude entire directories via .ai-bomignore.

New annotations
---------------
  # ai-bom: ignore       place at end of any line; suppresses SDK
                          component detection on that line only.

  # ai-bom: ignore-file  place anywhere in the first 5 lines of a file;
                          suppresses SDK component detection for the
                          entire file.

Scope of suppression (deliberate design decision)
--------------------------------------------------
Suppression applies ONLY to SDK/component detection (shadow AI, import
patterns, usage patterns).  Hardcoded API key detection is unconditional
and fires regardless of any annotation.

Why this boundary?

Our first instinct was to suppress everything on an annotated line -- if
a developer says 'ignore this', ignore everything.  We challenged that
thinking: a hardcoded credential leak is a security finding, not a
false positive.  A developer tagging an import as intentional should not
inadvertently silence a leaked key sitting on the same line.  The two
concerns are categorically different:

  - SDK detection: 'Is this library present?'  Can be intentional and
    already reviewed.  False positives here are routine.

  - Hardcoded key: 'Is there a live credential in source?'  Cannot be
    intentional in any safe codebase.  False positives here are rare
    and the cost of a missed true positive is severe.

Suppressing shadow AI detection does not break the security intent of
the tool.  Suppressing credential detection would.

This mirrors how comparable tools handle the same tension:
  - bandit's #nosec suppresses rule violations but the project README
    explicitly warns against suppressing credential rules
  - detect-secrets has a separate allow-list mechanism specifically
    to prevent inline suppression of secrets
  - semgrep's nosemgrep follows the same pattern

Idiomatic precedent
-------------------
The annotation pattern follows established Python ecosystem conventions:
  flake8 / ruff  ->  # noqa
  mypy           ->  # type: ignore
  bandit         ->  # nosec

Use cases
---------
  - Tool self-scans: pattern definition files contain SDK names as
    string literals (e.g. ai-bom's own detectors/ directory).  These
    are the detection engine, not live SDK usage.
  - Test harnesses that import AI SDKs to test detection behavior.
  - Compatibility shim code that references SDK names for feature
    detection without loading them at runtime.
  - Documentation generators that embed SDK names as examples.

Tests added (8 new cases in TestInlineSuppression)
---------------------------------------------------
  - Line-level suppression suppresses SDK detection
  - Line-level suppression does NOT suppress hardcoded API key
  - File-level suppression does NOT suppress hardcoded API key
  - Suppressed lines do not affect other lines in the same file
  - File-level suppression skips all SDK detection in the file
  - File-level annotation honoured on lines 2-5, not only line 1
  - File-level annotation after line 5 has no effect
  - Files without any annotation are unaffected
@Automation-Dude Automation-Dude requested a review from Zie619 as a code owner March 24, 2026 19:59
@Zie619
Copy link
Copy Markdown
Contributor

Zie619 commented Apr 13, 2026

Thanks for this contribution, Jordan — the feature motivation and security reasoning are solid, and the test coverage is thorough. Before we can merge, a few things need to be addressed:

1. Substring check creates a false-negative bypass (must fix)

The current implementation uses:

if suppress_sdk_file or "# ai-bom: ignore" in line:

Because "# ai-bom: ignore" is a substring of "# ai-bom: ignore-file", a line-level ignore-file trailing comment also satisfies the line-level check. More importantly, the bare in check matches anywhere in the line — including inside string literals. Code that merely references the annotation text as data will have its SDK detection silently dropped.

Please use anchored regex matching instead:

import re
_INLINE_IGNORE_RE = re.compile(r"#\s*ai-bom:\s*ignore\b(?!-file)")
_FILE_IGNORE_RE   = re.compile(r"#\s*ai-bom:\s*ignore-file\b")

Compile these at module level and use .search(line) in the per-line checks. This is also more consistent with how # noqa and # type: ignore tolerate whitespace variations.

2. No CI checks ran on this branch (must fix)

gh pr checks shows no reported checks for the feat/inline-suppression-annotations branch. We require green CI before merge. Can you confirm the workflow ran in your fork and share the run URL? If it didn't trigger, please push a no-op commit to kick it off.

3. Suppression logic is duplicated across two scan loops (should fix)

The same suppression block is added to both _scan_single_source_file and _scan_source_files. Please extract the file-level check into a small module-level helper and use the compiled regex from point 1. This keeps suppression behaviour in one place for future changes.

4. Documentation needs updating

docs/configuration.md only documents .ai-bomignore. The new inline annotations are a user-facing feature and need a section there before this merges.

Happy to review a v2 once these are addressed — the core logic and test quality are in good shape. 🙏

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants